using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SilkSharp
{
	/*
	 * @author Dingxin Xu
	 */
	public class Silk_find_LPC_FLP
	{
		/*
		 * @param NLSF NLSFs.
		 * @param interpIndex NLSF interp. index for NLSF interp.
		 * @param prev_NLSFq Previous NLSFs, for NLSF interpolation.
		 * @param useInterpNLSFs Flag.
		 * @param LPC_order LPC order.
		 * @param x Input signal.
		 * @param subfr_length Subframe length incl preceeding samples.
		 */
		public static void SKP_Silk_find_LPC_FLP(
			float[] NLSF,             /* O    NLSFs                                   */
			int[] interpIndex,      /* O    NLSF interp. index for NLSF interp.     */
			float[] prev_NLSFq,       /* I    Previous NLSFs, for NLSF interpolation  */
			int useInterpNLSFs,     /* I    Flag                                    */
			int LPC_order,          /* I    LPC order                               */
			float[] x,                /* I    Input signal                            */
			int subfr_length        /* I    Subframe length incl preceeding samples */
		)
		{
			int k;
			float[] a = new float[ Silk_define.MAX_LPC_ORDER ];

			/* Used only for NLSF interpolation */
			double res_nrg, res_nrg_2nd, res_nrg_interp;
			float[] a_tmp = new float[ Silk_define.MAX_LPC_ORDER ], NLSF0 = new float[ Silk_define.MAX_LPC_ORDER ];
			float[] LPC_res = new float[ ( Silk_define.MAX_FRAME_LENGTH + Silk_define.NB_SUBFR * Silk_define.MAX_LPC_ORDER ) / 2 ];

			/* Default: No interpolation */
			interpIndex[ 0 ] = 4;

			/* Burg AR analysis for the full frame */
			res_nrg = Silk_burg_modified_FLP.SKP_Silk_burg_modified_FLP( a, x, 0, subfr_length, Silk_define.NB_SUBFR,
					Silk_define_FLP.FIND_LPC_COND_FAC, LPC_order );

			if( useInterpNLSFs == 1 )
			{

				/* Optimal solution for last 10 ms; subtract residual energy here, as that's easier than        */
				/* adding it to the residual energy of the first 10 ms in each iteration of the search below    */
				res_nrg -= Silk_burg_modified_FLP.SKP_Silk_burg_modified_FLP( a_tmp, x, ( Silk_define.NB_SUBFR / 2 ) * subfr_length,
					subfr_length, Silk_define.NB_SUBFR / 2, Silk_define_FLP.FIND_LPC_COND_FAC, LPC_order );

				/* Convert to NLSFs */
				Silk_wrappers_FLP.SKP_Silk_A2NLSF_FLP( NLSF, a_tmp, LPC_order );

				/* Search over interpolation indices to find the one with lowest residual energy */
				res_nrg_2nd = float.MaxValue;
				for( k = 3; k >= 0; k-- )
				{
					/* Interpolate NLSFs for first half */
					Silk_wrappers_FLP.SKP_Silk_interpolate_wrapper_FLP( NLSF0, prev_NLSFq, NLSF, 0.25f * k, LPC_order );

					/* Convert to LPC for residual energy evaluation */
					Silk_wrappers_FLP.SKP_Silk_NLSF2A_stable_FLP( a_tmp, NLSF0, LPC_order );

					/* Calculate residual energy with LSF interpolation */
					Silk_LPC_analysis_filter_FLP.SKP_Silk_LPC_analysis_filter_FLP( LPC_res, a_tmp, x, 0, 2 * subfr_length, LPC_order );
					res_nrg_interp =
						Silk_energy_FLP.SKP_Silk_energy_FLP( LPC_res, LPC_order, subfr_length - LPC_order ) +
						Silk_energy_FLP.SKP_Silk_energy_FLP( LPC_res, LPC_order + subfr_length, subfr_length - LPC_order );

					/* Determine whether current interpolated NLSFs are best so far */
					if( res_nrg_interp < res_nrg )
					{
						/* Interpolation has lower residual energy */
						res_nrg = res_nrg_interp;
						interpIndex[ 0 ] = k;
					}
					else if( res_nrg_interp > res_nrg_2nd )
					{
						/* No reason to continue iterating - residual energies will continue to climb */
						break;
					}
					res_nrg_2nd = res_nrg_interp;
				}
			}

			if( interpIndex[ 0 ] == 4 )
			{
				/* NLSF interpolation is currently inactive, calculate NLSFs from full frame AR coefficients */
				Silk_wrappers_FLP.SKP_Silk_A2NLSF_FLP( NLSF, a, LPC_order );
			}

		}
	}
}
